package net.chrisrichardson.ec2deployer.cluster

import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.core.*
import net.chrisrichardson.ec2deployer.applications.*


class AppServerTierTest extends GroovyTestCase {

    MockFor mockEc2
    AWSProperties awsProperties
    ClusterSpec clusterSpec
    MockFor mockDatabaseTier
    MockFor mockMySqlServer
    def masterMySqlServer
    MockFor mockEc2Server
    MockFor mockTomcatServer
    EC2Server tomcatInstance

    MockFor mockWebApp

    public void setUp() {
        mockEc2 = new MockFor(EC2.class)
        mockDatabaseTier = new MockFor(DatabaseTier)
        mockMySqlServer = new MockFor(MySqlServer)
        mockEc2Server = new MockFor(EC2Server)
        mockTomcatServer = new MockFor(TomcatServer)
        mockWebApp = new MockFor(WebApp)

        def props = new Properties()
        awsProperties = new AWSProperties(props)

        clusterSpec = makeClusterSpec()

    }

    private ClusterSpec makeClusterSpec() {
        return new ClusterSpec().tomcats(1).slaves(1).webApp('target/ptrack', "ptrack").catalinaOptsBuilder({builder, databasePrivateDnsName ->}).schema("ptrack", ["ptrack": "ptrack"])
    }

    public void testAssignHosts() {


        mockTomcatServer.use {
            mockMySqlServer.use {
                mockDatabaseTier.use {
                    def ec2 = new EC2(awsProperties)
                    def tomcatInstance = new EC2Server()
                    def hosts = new ClusterHosts(tomcats: [tomcatInstance])
                    masterMySqlServer = new MySqlServer()
                    def databaseTier = new DatabaseTier(ec2, clusterSpec)
                    def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                    def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)
                    appServerTier.assignHosts(hosts)

                    assertEquals 1, appServerTier.tomcats.size
                }
            }
        }

    }

    public void testStart() {
        def ec2 = new EC2(awsProperties)

        mockTomcatServer.demand.startTomcat {}
        mockTomcatServer.demand.waitUntilRunning {}

        mockTomcatServer.use {
            mockMySqlServer.use {
                mockDatabaseTier.use {
                    def tomcatInstance = new EC2Server()
                    def hosts = new ClusterHosts(tomcats: [tomcatInstance])

                    masterMySqlServer = new MySqlServer()
                    def databaseTier = new DatabaseTier(ec2, clusterSpec)
                    def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                    def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)
                    appServerTier.assignHosts(hosts)

                    appServerTier.start()

                }
            }
        }

    }

    public void testMakeSpringApplicationPlatformServer() {
        def props = new Properties()
        props.setProperty("appServerClass", SpringSourceDmServer.class.name)
        awsProperties = new AWSProperties(props)


        def ec2 = new EC2(awsProperties)


        mockMySqlServer.use {
            mockDatabaseTier.use {
                def tomcatInstance = new EC2Server()
                def hosts = new ClusterHosts(tomcats: [tomcatInstance])

                masterMySqlServer = new MySqlServer()
                def databaseTier = new DatabaseTier(ec2, clusterSpec)
                def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)

                def sapServer = appServerTier.makeTomcat(tomcatInstance)
                assert sapServer instanceof SpringSourceDmServer
            }
        }

    }

    public void testSaveState() {

        mockTomcatServer.demand.getHost {-> tomcatInstance}
        mockEc2Server.demand.getInstanceId {"i-tomcat"}

        mockMySqlServer.use {
            mockDatabaseTier.use {
                mockTomcatServer.use {
                    mockEc2Server.use {
                        def ec2 = new EC2(awsProperties)
                        tomcatInstance = new EC2Server()
                        def hosts = new ClusterHosts(tomcats: [tomcatInstance])
                        masterMySqlServer = new MySqlServer()
                        def databaseTier = new DatabaseTier(ec2, clusterSpec)
                        def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                        def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)
                        appServerTier.assignHosts(hosts)

                        def state = [:]
                        appServerTier.saveState(state)
                        assertEquals([tomcats: ["i-tomcat"]], state)
                    }
                }
            }
        }

    }

    public void testRestoreState() {


        mockEc2.demand.findInstance {id ->
            assertEquals "i-tomcat", id
            tomcatInstance
        }

        mockEc2.demand.getAwsProperties { awsProperties }

        mockEc2.use {
            mockMySqlServer.use {
                mockDatabaseTier.use {
                    mockEc2Server.use {
                        def ec2 = new EC2(awsProperties)
                        tomcatInstance = new EC2Server()
                        masterMySqlServer = new MySqlServer()
                        def databaseTier = new DatabaseTier(ec2, clusterSpec)
                        def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                        def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)

                        def state = [tomcats: ["i-tomcat"]]
                        appServerTier.restoreState(state)

                        assertEquals 1, appServerTier.tomcats.size
                        assertEquals tomcatInstance, appServerTier.tomcats[0].host
                    }
                }
            }
        }

    }

    public void testUploadWebAppsToS3() {
        def ec2 = new EC2(awsProperties)

        mockWebApp.demand.uploadToS3 {AWSProperties awsProperties, String bucketPrefix ->
            assertEquals "myPrefix", bucketPrefix
        }

        mockWebApp.use {
            ClusterSpec clusterSpec = makeClusterSpec()
            clusterSpec.bucketPrefix("myPrefix")
            def databaseTier = new DatabaseTier(ec2, clusterSpec)
            def terracottaTier = new TerracottaTier(ec2, clusterSpec)
            def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)
            appServerTier.uploadWebAppsToS3()
        }

    }

    public void testAddAppServers() {

        mockEc2Server.demand.waitUntilRunning {}
        mockTomcatServer.demand.startTomcat {}
        mockTomcatServer.demand.waitUntilRunning {}
        mockEc2Server.demand.executeScriptText {}

        mockDatabaseTier.use {
            mockEc2Server.use {
                mockTomcatServer.use {
                    mockEc2.use {

                        mockEc2.demand.newServers {n, type -> [new EC2Server()]}
                        mockEc2.demand.getAwsProperties { awsProperties }
                        mockEc2.demand.getAwsProperties { awsProperties }

                        def ec2 = new EC2(awsProperties)

                        def clusterSpec = makeClusterSpec()

                        def databaseTier = new DatabaseTier(ec2, clusterSpec)
                        def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                        def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)
                        appServerTier.addAppServers 1
                    }
                }
            }
        }

    }

    public void testStartTomcatOn() {


        mockTomcatServer.demand.startTomcat {}
        mockTomcatServer.demand.waitUntilRunning {}

        mockEc2Server.demand.getInstanceId {-> "-i1"}
        mockEc2Server.demand.getInstanceId {-> "-i2"}
        mockEc2Server.demand.getInstanceId {-> "-i1"}

        mockEc2.demand.getAwsProperties { awsProperties }

        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            mockEc2Server.use {
                mockTomcatServer.use {
                    mockMySqlServer.use {
                        mockDatabaseTier.use {
                            def tomcatInstance = new EC2Server()

                            mockTomcatServer.demand.getHost { tomcatInstance }
                            mockTomcatServer.demand.getHost { tomcatInstance }
                            mockTomcatServer.demand.startTomcat {}
                            mockTomcatServer.demand.waitUntilRunning {}

                            def hosts = new ClusterHosts(tomcats: [tomcatInstance])

                            masterMySqlServer = new MySqlServer()
                            def databaseTier = new DatabaseTier(ec2, clusterSpec)
                            def terracottaTier = new TerracottaTier(ec2, clusterSpec)
                            def appServerTier = new AppServerTier(ec2, clusterSpec, databaseTier, terracottaTier)

                            appServerTier.assignHosts(hosts)

                            def ec2Server = new EC2Server()
                            mockEc2.demand.newServers { number, type -> [ec2Server] }
                            mockEc2.demand.getAwsProperties { awsProperties }

                            appServerTier.start()

                            appServerTier.addAppServer(ec2)
                            appServerTier.startTomcatOn([ec2Server])

                        }
                    }
                }
            }
        }
    }

}